﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TankController;
using TankController.Dominio;

namespace TankController
{
    public partial class UcControleControladorMF : UserControl
    {
        private const int CONTROLADOR_MF = 0;
        private const int CONFIGURA_KI = 1;
        private const int CONFIGURA_KD = 2;

        private FormControle formControle;
        private TipoPosicaoControlador tipoPosicao;
        
        public UcControleControladorMF()
        {
            InitializeComponent();
        }

        public UcControleControladorMF(FormControle formControle, TipoPosicaoControlador tipoPosicao)
            : this()
        {
            this.formControle = formControle;
            this.tipoPosicao = tipoPosicao;

            ConfigurarAmbiente(tipoPosicao);
        }

        private void ConfigurarAmbiente(TipoPosicaoControlador tipoPosicao)
        {
            switch (tipoPosicao)
            {
                case TipoPosicaoControlador.Unico:
                    gbxPrincipal.Text = "Controlador";
                    break;
                case TipoPosicaoControlador.Controlador1:
                    gbxPrincipal.Text = "Controlador 1";
                    break;
                case TipoPosicaoControlador.Controlador2:
                    gbxPrincipal.Text = "Controlador 2";
                    break;
                default:
                    throw new ApplicationException("Tipo de posição do controlador inválida.");
            }
        }

        public void ValidarCampos()
        {
            double parseResult;

            ControladorMalhaFechada controladorMF = GetConfiguracao()[CONTROLADOR_MF] as ControladorMalhaFechada;

            if (!double.TryParse(txtKp.Text.Replace('.', ','), out parseResult))
            {
                throw new ApplicationException("Valor de Kp inválido.");
            }

            if ((controladorMF is ControladorPI ||
                controladorMF is ControladorPID ||
                controladorMF is ControladorPI_D) &&
                rbtKi.Checked && !double.TryParse(txtKi.Text.Replace('.', ','), out parseResult))
            {
                throw new ApplicationException("Valor de Ki inválido.");
            }

            if ((controladorMF is ControladorPI ||
                controladorMF is ControladorPID ||
                controladorMF is ControladorPI_D) &&
                rbtTi.Checked && !double.TryParse(txtTi.Text.Replace('.', ','), out parseResult))
            {
                throw new ApplicationException("Valor de Ti inválido.");
            }

            if ((controladorMF is ControladorPD ||
                controladorMF is ControladorPID ||
                controladorMF is ControladorPI_D) &&
                rbtKd.Checked && !double.TryParse(txtKd.Text.Replace('.', ','), out parseResult))
            {
                throw new ApplicationException("Valor de Kd inválido.");
            }

            if ((controladorMF is ControladorPD ||
                controladorMF is ControladorPID ||
                controladorMF is ControladorPI_D) &&
                rbtTd.Checked && !double.TryParse(txtTd.Text.Replace('.', ','), out parseResult))
            {
                throw new ApplicationException("Valor de Td inválido.");
            }
        }

        public void MontarControlador()
        {
            ControladorMalhaFechada controladorMF = GetConfiguracao()[CONTROLADOR_MF] as ControladorMalhaFechada;

            double kp = 0;
            double ki = 0;
            double kd = 0;

            if (controladorMF is ControladorP)
            {
                kp = double.Parse(txtKp.Text.Replace('.', ','));

                (controladorMF as ControladorP).SetGanho(kp);
            }
            else if (controladorMF is ControladorPI)
            {
                kp = double.Parse(txtKp.Text.Replace('.', ','));
                ki = rbtKi.Checked ? double.Parse(txtKi.Text.Replace('.', ',')) : 1 / double.Parse(txtTi.Text.Replace('.', ','));

                (controladorMF as ControladorPI).SetGanho(kp, ki);
            }
            else if (controladorMF is ControladorPD)
            {
                kp = double.Parse(txtKp.Text.Replace('.', ','));
                kd = rbtKd.Checked ? double.Parse(txtKd.Text.Replace('.', ',')) : 1 / double.Parse(txtTd.Text.Replace('.', ','));

                (controladorMF as ControladorPD).SetGanho(kp, kd);
            }
            else if (controladorMF is ControladorPID)
            {
                kp = double.Parse(txtKp.Text.Replace('.', ','));
                ki = rbtKi.Checked ? double.Parse(txtKi.Text) : 1 / double.Parse(txtTi.Text.Replace('.', ','));
                kd = rbtKd.Checked ? double.Parse(txtKd.Text) : 1 / double.Parse(txtTd.Text.Replace('.', ','));

                (controladorMF as ControladorPID).SetGanho(kp, ki, kd);
            }
            else if (controladorMF is ControladorPI_D)
            {
                kp = double.Parse(txtKp.Text.Replace('.', ','));
                ki = rbtKi.Checked ? double.Parse(txtKi.Text.Replace('.', ',')) : 1 / double.Parse(txtTi.Text.Replace('.', ','));
                kd = rbtKd.Checked ? double.Parse(txtKd.Text.Replace('.', ',')) : 1 / double.Parse(txtTd.Text.Replace('.', ','));

                (controladorMF as ControladorPI_D).SetGanho(kp, ki, kd);
            }
            else
            {
                throw new ApplicationException("Tipo de controlador de malha fechada inválido.");
            }
        }

        public void AtualizarCampos()
        {
            Object[] configuracao = GetConfiguracao();
            ControladorMalhaFechada controladorMF = configuracao[CONTROLADOR_MF] as ControladorMalhaFechada;
            Boolean configuraKi = (Boolean)configuracao[CONFIGURA_KI];
            Boolean configuraKd = (Boolean)configuracao[CONFIGURA_KD];

            lblControlador.Text = controladorMF.Descricao;

            if (controladorMF is ControladorP)
            {
                gbxAcoes.Enabled = true;

                pnlAcaoProporcional.Enabled = true;
                pnlAcaoIntegral.Enabled = false;
                pnlAcaoDerivativa.Enabled = false;

                txtKp.Text = (controladorMF as ControladorP).Kp.ToString();
            }
            else if (controladorMF is ControladorPI)
            {
                gbxAcoes.Enabled = true;

                pnlAcaoProporcional.Enabled = true;
                pnlAcaoIntegral.Enabled = true;
                pnlAcaoDerivativa.Enabled = false;

                txtKp.Text = (controladorMF as ControladorPI).Kp.ToString();

                if (configuraKi)
                {
                    rbtKi.Checked = true;
                    txtTi.Text = "";
                    txtKi.Text = (controladorMF as ControladorPI).Ki.ToString();
                }
                else
                {
                    rbtTi.Checked = true;
                    txtKi.Text = "";
                    txtTi.Text = (1 / (controladorMF as ControladorPI).Ki).ToString();
                }
            }
            else if (controladorMF is ControladorPD)
            {
                gbxAcoes.Enabled = true;

                pnlAcaoProporcional.Enabled = true;
                pnlAcaoIntegral.Enabled = false;
                pnlAcaoDerivativa.Enabled = true;

                txtKp.Text = (controladorMF as ControladorPD).Kp.ToString();

                if (configuraKd)
                {
                    rbtKd.Checked = true;
                    txtTd.Text = "";
                    txtKd.Text = (controladorMF as ControladorPD).Kd.ToString();
                }
                else
                {
                    rbtTd.Checked = true;
                    txtKd.Text = "";
                    txtTd.Text = (1 / (controladorMF as ControladorPD).Kd).ToString();
                }
            }
            else if (controladorMF is ControladorPID)
            {
                gbxAcoes.Enabled = true;

                pnlAcaoProporcional.Enabled = true;
                pnlAcaoIntegral.Enabled = true;
                pnlAcaoDerivativa.Enabled = true;

                txtKp.Text = (controladorMF as ControladorPID).Kp.ToString();

                if (configuraKi)
                {
                    rbtKi.Checked = true;
                    txtKi.Text = (controladorMF as ControladorPID).Ki.ToString();
                    txtTi.Text = "";
                }
                else
                {
                    rbtTi.Checked = true;
                    txtKi.Text = "";
                    txtTi.Text = (1 / (controladorMF as ControladorPID).Ki).ToString();
                }

                if (configuraKd)
                {
                    rbtKd.Checked = true;
                    txtKd.Text = (controladorMF as ControladorPID).Kd.ToString();
                    txtTd.Text = "";
                }
                else
                {
                    rbtTd.Checked = true;
                    txtKd.Text = "";
                    txtTd.Text = (1 / (controladorMF as ControladorPID).Kd).ToString();
                }
            }
            else if (controladorMF is ControladorPI_D)
            {
                gbxAcoes.Enabled = true;

                pnlAcaoProporcional.Enabled = true;
                pnlAcaoIntegral.Enabled = true;
                pnlAcaoDerivativa.Enabled = true;

                txtKp.Text = (controladorMF as ControladorPI_D).Kp.ToString();

                if (configuraKi)
                {
                    rbtKi.Checked = true;
                    txtKi.Text = (controladorMF as ControladorPI_D).Ki.ToString();
                    txtTi.Text = "";
                }
                else
                {
                    rbtTi.Checked = true;
                    txtKi.Text = "";
                    txtTi.Text = (1 / (controladorMF as ControladorPI_D).Ki).ToString();
                }

                if (configuraKd)
                {
                    rbtKd.Checked = true;
                    txtKd.Text = (controladorMF as ControladorPI_D).Kd.ToString();
                    txtTd.Text = "";
                }
                else
                {
                    rbtTd.Checked = true;
                    txtKd.Text = "";
                    txtTd.Text = (1 / (controladorMF as ControladorPI_D).Kd).ToString();
                }
            }
            else
            {
                throw new ApplicationException("Tipo de controlador de malha fechada inválido.");
            }
        }

        private void rbtAcaoIntegrativa_CheckedChanged(object sender, EventArgs e)
        {
            if (rbtKi.Checked)
            {
                txtKi.Enabled = true;
                txtTi.Enabled = false;

                rbtKd.Checked = true;

                SetConfiguracaoKi(true);
            }
            else
            {
                txtKi.Enabled = false;
                txtTi.Enabled = true;

                rbtTd.Checked = true;

                SetConfiguracaoKi(false);
            }
        }

        private void rbtAcaoDerivativa_CheckedChanged(object sender, EventArgs e)
        {
            if (rbtKd.Checked)
            {
                txtKd.Enabled = true;
                txtTd.Enabled = false;

                rbtKi.Checked = true;

                SetConfiguracaoKd(true);
            }
            else
            {
                txtKd.Enabled = false;
                txtTd.Enabled = true;

                rbtTi.Checked = true;

                SetConfiguracaoKd(false);
            }
        }

        private void lklSelecionarControlador_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            switch (tipoPosicao)
            {
                case TipoPosicaoControlador.Unico:
                case TipoPosicaoControlador.Controlador1:
                    formControle.MostrarTelaConfigurar(TipoAba.Controlador1);

                    break;
                case TipoPosicaoControlador.Controlador2:
                    formControle.MostrarTelaConfigurar(TipoAba.Controlador2);

                    break;
                default:
                    throw new ApplicationException("Tipo de posição do controlador inválida.");
            }
        }

        private void txtParametro_KeyPress(object sender, KeyPressEventArgs e)
        {
            try
            {
                if (e.KeyChar == (char)Keys.Return)
                {
                    ValidarCampos();

                    MontarControlador();

                    e.Handled = true;
                }
            }
            catch (ApplicationException apex)
            {
                MessageBox.Show(apex.Message, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private Object[] GetConfiguracao()
        {
            switch (tipoPosicao)
            {
                case TipoPosicaoControlador.Unico:
                case TipoPosicaoControlador.Controlador1:
                    return new Object[] { Global.Controlador1, Global.ConfiguraKi1, Global.ConfiguraKd1 };
                case TipoPosicaoControlador.Controlador2:
                    return new Object[] { Global.Controlador2, Global.ConfiguraKi2, Global.ConfiguraKd2 };
                default:
                    throw new ApplicationException("Tipo de posição do controlador inválida.");
            }
        }

        private void SetConfiguracaoKi(Boolean configuraKi)
        {
            switch (tipoPosicao)
            {
                case TipoPosicaoControlador.Unico:
                case TipoPosicaoControlador.Controlador1:
                    Global.ConfiguraKi1 = configuraKi;

                    break;
                case TipoPosicaoControlador.Controlador2:
                    Global.ConfiguraKi2 = configuraKi;

                    break;
                default:
                    throw new ApplicationException("Tipo de posição do controlador inválida.");
            }
        }

        private void SetConfiguracaoKd(Boolean configuraKd)
        {
            switch (tipoPosicao)
            {
                case TipoPosicaoControlador.Unico:
                case TipoPosicaoControlador.Controlador1:
                    Global.ConfiguraKd1 = configuraKd;

                    break;
                case TipoPosicaoControlador.Controlador2:
                    Global.ConfiguraKd2 = configuraKd;

                    break;
                default:
                    throw new ApplicationException("Tipo de posição do controlador inválida.");
            }
        }

        internal void HabilitarControlador(Boolean habilitar)
        {
            lklMudarControlador.Enabled = habilitar;
        }
    }
}
